/**
 * @author alex
 */

Namespace("sketch.framework");

(function($, fwk) {

    fwk.ResizeDimension = {
        None:0,
        Vertical:1,
        Horizontal:2,
        Both:3
    };
    // constructor
    fwk.UIElement = klass(null, {
        _constructor:function() {
            var selected = false,
                that = this;

            // public variables
            this.decorators = [];
            this.properties = new fwk.Properties(this);
            this.properties.createProperty("width", "Element width", 0).validate(function(event) {
                var mw = that.minWidth();
                if (event.newValue < mw) {
                    event.ok = false;
                    event.changedValue = mw;
                }
            });
            this.properties.createProperty("height", "Element height", 0).validate(function(event) {
                var mh = that.minHeight();
                if (event.newValue < mh) {
                    event.ok = false;
                    event.changedValue = mh;
                }
            });
            this.properties.createProperty("left", "Element left position", 0);
            this.properties.createProperty("top", "Element top position", 0);
            this.properties.createProperty("zOrder", "Element zOrder", null);
            this.properties.createProperty("visible", "Element visibility", true);
            this.properties.createProperty("parent", "Element parent", null);
            this.properties.createProperty("margin", "Margin", new fwk.Box());
            this.properties.createProperty("canSelect", "Is selectable", true);
            this.properties.createProperty("opacity", "Opacity", 1);
            this.properties.createProperty("minWidth", "Min width", 1);
            this.properties.createProperty("minHeight", "Min height", 1);
            this.properties.createProperty("clipSelf", "Clip self", false);
            this.properties.createProperty("canScaleSize", "Can scale size", true);
            this.properties.createProperty("shadow", "Element shadow", new fwk.ContextModifier());
            this.properties.propertyChanged.bind(function() {
                that.invalidate();
            });

            this.onresize = fwk.EventHelper.createEvent();
            this._draggingOver = false;
            this._draggingData = null;

            this.properties.createProperty("horizontalAlignment", "Horizontal alignment", "stretch")
                .possibleValues({stretch: "stretch", left: "Left", center: "Center", right: "Right"});

            this.properties.createProperty("verticalAlignment", "Vertical alignment", "stretch")
                .possibleValues({stretch: "stretch", top: "Top", center: "Center", bottom: "Bottom"});

            // public methods
            this.canSelect = function (/*bool*/value) {
                if (arguments.length === 0) {
                    return this.properties.canSelect() && !this.parent().locked();
                }
                this.properties.canSelect(value);
            };
        },
        startDrag : function(event) {

        },
        stopDrag : function(event) {

        },
        dragTo : function(event) {
            this.position(event);
        },
        dragging : function(event) {
        },
        draggingEnter : function(event) {
        },
        draggingLeft: function(event) {
        },
        startDragging : function(event) {
        },
        stopDragging : function(event) {
        },
        dropOn : function(event) {
        },
        getDropData : function(event) {
            return null;
        },
        getSnapPoints : function() {
            var rect = this.getBoundaryRectGlobal();
            var left = rect.x,
                top = rect.y,
                width = rect.width,
                height = rect.height;
            return {
                xs:[left, left + width],
                ys:[top, top + height],
                center:{x:left + width / 2, y:top + height / 2}
            };
        },
        position : function(pos) {
            if (arguments.length === 0) {
                return {x:this.left(), y:this.top()};
            }
            this.left(pos.x);
            this.top(pos.y);
        },
        addDecorator : function(decorator) {
            this.decorators.push(decorator);
            decorator.attach(this);
        },
        removeDecorator : function(decorator) {
            for (var i = 0, max = this.decorators.length; i < max; i++) {
                if (this.decorators[i] === decorator) {
                    this.decorators[i].detach();
                    this.decorators.splice(i, 1);
                    break;
                }
            }
        },
        removeDecoratorByType : function(type) {
            for (var i = 0, max = this.decorators.length; i < max; i++) {
                if (this.decorators[i] instanceof type) {
                    this.decorators[i].detach();
                    this.decorators.splice(i, 1);
                    break;
                }
            }
        },
        getBoundaryRect : function() {
            return {
                x : this.left(),
                y : this.top(),
                width : this.width(),
                height : this.height()
            }
        },
        getBoundaryRectGlobal: function() {
            var rect = this.getBoundaryRect();
            var globalPos = this.parent().local2global(rect);
            rect.x = globalPos.x;
            rect.y = globalPos.y;

            return rect;
        },
        hitTest : function(x, y) {
            var left = this.left();
            var top = this.top();
            return x >= left && x <= left + this.width() && y >= top && y <= top + this.height();
        },
        draw:function(context) {
            var x = this.left(),
                y = this.top(),
                w = this.width(),
                h = this.height();

            context.save();
            context.globalAlpha = this.opacity();
            var that = this;
            if(this.clipSelf()){
                context.rectPath(x, y, w, h);
                context.clip();
            }

            if(!this.canScaleSize()){
                var scale = this.view().scale();
                context.scale(1/scale, 1/scale);
                context.translate((x + w/2)*(scale - 1), (y+w/2)*(scale - 1));
            }

            this.drawSelf(context);
            context.restore();

            context.save();
            for (var i = 0, j = this.decorators.length; i < j; ++i) {
                this.decorators[i].draw(context);
            }
            context.restore();
        },
        drawSelf : function(context) {
        },
        mousemove : function(event) {
            if (this.editor != null) {
                event.handled = true;
            }
        },
        mouseup : function(event) {
        },
        mousedown : function(event) {
            if (this.editor != null) {
                this.properties.set(this.editorProperty.propertyName, this.editor.value());
                this.editor.hide();
                this.parent().releaseMouse(this);
                event.handled = true;
                this.editor = null;
                this.editorProperty = null;
            }
        },
        dblclick : function(event) {
        },
        click : function(event) {
        },
        captureMouse : function() {
            this.parent().captureMouse(this);
        },
        releaseMouse : function() {
            this.parent().releaseMouse(this);
        },
        canMultiSelect : function() {
            return true;
        },
        zOrder : function(/*int*/value) {
            return this.properties.zOrder(value);
        },
        left : function(/*int*/value) {
            return this.properties.left(value);
        },
        top : function(/*set*/value) {
            return this.properties.top(value);
        },
        width : function (value) {
            return this.properties.width(value);
        },
        height : function (/*int*/value) {
            return this.properties.height(value);
        },
        right: function() {
            return this.left() + this.width();
        },
        bottom: function() {
            return this.top() + this.height();
        },
        visible : function (/*bool*/value) {
            return this.properties.visible(value);
        },
        clipSelf:function(/*bool*/value){
            return this.properties.clipSelf(value);
        },
        parent : function (/*UIElement*/value) {
            return this.properties.parent(value);
        },
        opacity : function (/*double*/value) {
            return this.properties.opacity(value);
        },
        shadow : function (/*double*/value) {
            return this.properties.shadow(value);
        },
        minWidth : function (/*Number*/value) {
            return this.properties.minWidth(value);
        },
        minHeight : function (/*Number*/value) {
            return this.properties.minHeight(value);
        },
        canScaleSize: function(/*bool*/value){
            return this.properties.canScaleSize(value);
        },
        resize : function(/*Rect*/rect) {
            this.left(rect.x);
            this.top(rect.y);
            this.width(rect.width);
            this.height(rect.height);
            this.onresize(rect);
        },
        getType:function() {
            return "UIElement";
        },
        applyVisitor:function(/*Visitor*/callback) {
            return callback(this);
        },
        canAccept:function(element) {
            return false;
        },
        boxProperties: function() {
            return {
                left: this.properties.left,
                top: this.properties.top,
                width: this.properties.width,
                height: this.properties.height
            };
        },
        sizeProperties: function() {
            return {
                width: this.properties.width,
                height: this.properties.height
            };
        },
        view:function() {
            var parent = this.parent();
            if (parent === null) {
                return null;
            }
            return parent.view();
        },
        invalidate:function() {
            if (!this._lockInvalidate) {
                var parent = this.parent();
                if (parent !== null) {
                    parent.invalidate();
                }
            }
        },
        lockInvalidate:function() {
            this._lockInvalidate = true;
        },
        unlockInvalidate:function() {
            this._lockInvalidate = false;
        },
        margin: function(value) {
            return this.properties.margin(value);
        },
        bindToBox: function(box) {
            box.left.changedEvent.bind(this.properties.left.bindingPoint);
            box.top.changedEvent.bind(this.properties.top.bindingPoint);
            box.width.changedEvent.bind(this.properties.width.bindingPoint);
            box.height.changedEvent.bind(this.properties.height.bindingPoint);
            this.properties.left(box.left());
            this.properties.top(box.top());
            this.properties.width(box.width());
            this.properties.height(box.height());
        },
        bindToSize: function(box) {
            box.width.changedEvent.bind(this.properties.width.bindingPoint);
            box.height.changedEvent.bind(this.properties.height.bindingPoint);
            this.properties.width(box.width());
            this.properties.height(box.height());
        },
        showInplaceEditor: function(property) {
            this.parent().captureMouse(this);
            this.editor = new fwk.text.InplaceEditor(this.parent(), true);
            this.editorProperty = property;
            var rect = this.getBoundaryRectGlobal();
            var scale = this.view().scale();

            this.editor.show(property.value, rect.x * scale, rect.y * scale, rect.width * scale, rect.height * scale);
        },
        isDescendantOrSame:function(element) {
            var current = this;
            do{
                if (current === element) {
                    return true;
                }
                var type = typeof current.parent;
                if (type !== 'function') {
                    return false;
                }
                current = current.parent();
            } while (current !== null);

            return false;
        },
        horizontalAlignment: function(value) {
            return this.properties.horizontalAlignment(value);
        },
        verticalAlignment: function(value) {
            return this.properties.verticalAlignment(value);
        },
        index:function() {
            var that = this;
            var ret = 0;
            this.parent().children.each(function(idx, element) {
                if (that === element) {
                    ret = idx;
                    return false;
                }
            });

            return ret;
        },
        shallowCopy: function() {
            var clone = new this.Klass();
            this.properties.copyTo(clone.properties);
            clone.width(this.width());
            clone.height(this.height());
            return clone;
        },
        clone: function() {
            return this.shallowCopy();
        },
        cursor:function() {
            return null;
        },
        resizeDimensions:function() {
            return fwk.ResizeDimension.Both;
        },
        getVisualActions: function() {
            return null;
        },
        init:function(values){
            this.properties.init(values);
            return this;
        }
    });

})(jQuery, sketch.framework);
